﻿//------------------------------------------------------------------------------
// Triple A OO-CAML library
// Create your SharePoint CAML queries easier
// 
// 
// How to use:
// Instead of typing:
//      string caml = "<Where><Eq><FieldRef Name='Title' /><Value Type='Text'>Test</Value></Eq></Where>";
// use the easy OO-CAML:
//      string caml = SPCaml.Where(
//                       SPCaml.Eq(
//                          SPCaml.FielRef("Title"),
//                          SPCaml.Value("Test")
//                       )
//                    ).ToCaml();
//------------------------------------------------------------------------------

namespace TripleA.SharePoint.CAML
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;

    /// <summary>
    /// Represents the possible values for a membership type
    /// </summary>
    public enum MembershipType
    {
        /// <summary>
        /// Specifies the membership for all SharePoint web users
        /// </summary>
        SPWebAllUsers,

        /// <summary>
        /// Specifies the membership for the group
        /// </summary>
        SPGroup,

        /// <summary>
        /// Specifies the membership for all SharePoint web groups
        /// </summary>
        SPWebGroups,

        /// <summary>
        /// Specifies the membership for the user's group
        /// </summary>
        CurrentUserGroups,

        /// <summary>
        /// Specifies the membership for the SharePoint web user
        /// </summary>
        SPWebUsers,
    }

    #region CAML Interfaces

    /// <summary>
    /// Represents a CAML element
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct use")]
    public interface ICamlElement
    {
        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct use")]
        string ToCaml();
    }

    /// <summary>
    /// Represent a CAML element that can be used in <code>And</code> or <code>Or</code>
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1040:AvoidEmptyInterfaces", Justification = "There wasn't an other option than to leave this interface empty")]
    public interface IWhereChild : ICamlElement
    {
    }

    /// <summary>
    /// Represent a CAML element that can be used in <code>Value</code>
    /// </summary>
    public interface IValueChild : ICamlElement
    {
        /// <summary>
        /// Gets the type of the value
        /// </summary>
        string Type
        {
            get;
        }
    }

    #endregion

    /// <summary>
    /// Singleton class containing all the CAML objects
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct use"),
    DebuggerStepThrough]
    public static partial class SPCaml
    {
        #region Logical Joins

        /// <summary>
        /// Used within the <code>Where</code> element to group filters in a query for a view.
        /// </summary>
        /// <param name="child1">First child for this And</param>
        /// <param name="child2">Second child for this And</param>
        /// <returns>An <see cref="And"/> object for group filtering</returns>
        public static And And(IWhereChild child1, IWhereChild child2)
        {
            return new And(child1, child2);
        }

        /// <summary>
        /// Used within the <code>Where</code> element to group filters in a query.
        /// </summary>
        /// <param name="child1">First child for this Or</param>
        /// <param name="child2">Second child for this Or</param>
        /// <returns>An <see cref="Or"/> object for group filtering</returns>
        public static Or Or(IWhereChild child1, IWhereChild child2)
        {
            return new Or(child1, child2);
        }

        #endregion

        #region Group/Order Operations

        /// <summary>
        /// Contains a Group By section for grouping the data returned through a query in a list view.
        /// </summary>
        /// <param name="fieldRef">A <see cref="FieldRef"/> Object</param>
        /// <returns>A <see cref="GroupBy"/> CAML Object</returns>
        public static GroupBy GroupBy(FieldRef fieldRef)
        {
            return new GroupBy(fieldRef);
        }

        /// <summary>
        /// Contains a Group By section for grouping the data returned through a query in a list view.
        /// </summary>
        /// <param name="fieldRef">A <see cref="FieldRef"/> CAML Object</param>
        /// <param name="collapse">Optional Boolean. TRUE for the Group By section in the list view to be collapsed by default.</param>
        /// <returns>A <see cref="GroupBy"/> CAML Object</returns>
        public static GroupBy GroupBy(FieldRef fieldRef, bool? collapse)
        {
            return new GroupBy(fieldRef, collapse);
        }

        /// <summary>
        /// Determines the sort order for a query. The OrderBy element contains a group of FieldRef elements.
        /// </summary>
        /// <param name="fieldRef">A list of <see cref="FieldRef"/> CAML Objects</param>
        /// <returns>A <see cref="OrderBy"/> CAML Object</returns>
        public static OrderBy OrderBy(params FieldRef[] fieldRef)
        {
            return OrderBy(null, null, fieldRef);
        }

        /// <summary>
        /// Determines the sort order for a query. The OrderBy element contains a group of FieldRef elements.
        /// </summary>
        /// <param name="overrideOrderBy">Value indication whenever to override</param>
        /// <param name="useIndexForOrderBy">Value indicating whenever to use index for the order by</param>
        /// <param name="fieldRef">A <see cref="FieldRef"/> CAML Object</param>
        /// <returns>A <see cref="OrderBy"/> CAML Object</returns>
        public static OrderBy OrderBy(bool? overrideOrderBy, bool? useIndexForOrderBy, params FieldRef[] fieldRef)
        {
            return new OrderBy(overrideOrderBy, useIndexForOrderBy, fieldRef);
        }

        #endregion

        #region Value Child Elements

        /// <summary>
        /// Construct a new today element
        /// </summary>
        /// <returns>A <see cref="Today"/> CAML object</returns>
        public static Today Today()
        {
            return new Today();
        }

        /// <summary>
        /// Construct a new today element
        /// </summary>
        /// <param name="offset">Adds or subtracts the number of days that are specified by the positive or negative integer value.</param>
        /// <returns>A <see cref="Today"/> CAML object</returns>
        public static Today Today(int offset)
        {
            return new Today(offset);
        }

        /// <summary>
        /// Returns the current date and time.
        /// </summary>
        /// <returns>A <see cref="Now"/> CAML Object</returns>
        public static Now Now()
        {
            return new Now();
        }

        /// <summary>
        /// Contains the unique ID number of the currently authenticated user of a site, as defined in the UserInfo table of the content database.
        /// </summary>
        /// <returns>A <see cref="UserId"/> CAML object</returns>
        public static UserId UserId()
        {
            return new UserId();
        }

        #endregion

        #region Field Value Operators

        #region Values

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="child">Child used for the Value</param>
        /// <returns>A <see cref="Value"/> object to CAML</returns>
        public static Value Value(IValueChild child)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            return Value(child.Type, child.ToCaml(), null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="child">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever the data includes a time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(IValueChild child, bool? includeTimeValue)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            return Value(child.Type, child.ToCaml(), includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(int data)
        {
            return Value("Number", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(bool data)
        {
            return Value("Boolean", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(decimal data)
        {
            return Value("Number", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(double data)
        {
            return Value("Number", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(float data)
        {
            return Value("Number", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(long data)
        {
            return Value("Number", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(string data)
        {
            return Value("Text", data, null);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Value indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(int data, bool? includeTimeValue)
        {
            return Value("Number", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(bool data, bool? includeTimeValue)
        {
            return Value("Boolean", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(decimal data, bool? includeTimeValue)
        {
            return Value("Number", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(double data, bool? includeTimeValue)
        {
            return Value("Number", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(float data, bool? includeTimeValue)
        {
            return Value("Number", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(long data, bool? includeTimeValue)
        {
            return Value("Number", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(string data, bool? includeTimeValue)
        {
            return Value("Text", data, includeTimeValue);
        }

        /// <summary>
        /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
        /// </summary>
        /// <param name="type">Type of the value</param>
        /// <param name="data">Data for this value</param>
        /// <param name="includeTimeValue">Indication whenever to export the time value</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        public static Value Value(string type, object data, bool? includeTimeValue)
        {
            return new Value(type, data, includeTimeValue);
        }

        #endregion

        /// <summary>
        /// Represents a reference to a field within a query.
        /// </summary>
        /// <param name="name">Name of the Field</param>
        /// <returns>A <see cref="FieldRef"/> CAML object</returns>
        public static FieldRef FieldRef(string name)
        {
            return new FieldRef(name);
        }

        /// <summary>
        /// Represents a reference to a field within a query.
        /// </summary>
        /// <param name="name">Name of the Field</param>
        /// <param name="isLookupId">Value indication whenever this <see cref="FieldRef"/> object is a lookup Id </param>
        /// <returns>A <see cref="FieldRef"/> CAML object</returns>
        public static FieldRef FieldRef(string name, bool? isLookupId)
        {
            return new FieldRef(name, isLookupId);
        }

        /// <summary>
        /// Multiple Values
        /// </summary>
        /// <param name="value">Value to include into this Value</param>
        /// <param name="values">Optional multiple values</param>
        /// <returns>A <see cref="Value"/> CAML Object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "1#", Justification = "Values is the correct name in CAML")]
        public static Values Values(Value value, params Value[] values)
        {
            return new Values(value, values);
        }

        #endregion

        #region Comparison Operators
        /// <summary>
        /// Used within a query to return items that are empty (Null).
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <returns>A <see cref="IsNull"/> CAML object</returns>
        public static IsNull IsNull(FieldRef fieldRef)
        {
            return IsNull(fieldRef);
        }

        /// <summary>
        /// Specifies whether the value of a list item for the field specified by the FieldRef element is equal to one of the values specified by the Values element.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="In"/> CAML object</returns>
        public static In In(FieldRef fieldRef, Value value)
        {
            return new In(fieldRef, value);
        }

        /// <summary>
        /// Arithmetic operator that means "less than or equal to." The <see cref="Leq"/> element is used in view queries similarly to the <see cref="Eq"/> and <see cref="Geq"/> elements.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Leq"/> CAML Object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Leq", Justification = "Leq is correct as is in CAML")]
        public static Leq Leq(FieldRef fieldRef, Value value)
        {
            return new Leq(fieldRef, value);
        }

        /// <summary>
        /// If the specified field is a Lookup field that allows multiple values, specifies that the Value element is excluded from the list item for the field that is specified by the FieldRef element.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="NotIncludes"/> CAML object</returns>
        public static NotIncludes NotIncludes(FieldRef fieldRef, Value value)
        {
            return new NotIncludes(fieldRef, value);
        }

        /// <summary>
        /// Defines a filter based on the type of membership for the user.
        /// </summary>
        /// <param name="type">Specifies the type of membership for the user. Possible values include the following:</param>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <returns>A <see cref="Membership"/> CAML object</returns>
        public static Membership Membership(MembershipType type, FieldRef fieldRef)
        {
            return new Membership(type, fieldRef);
        }

        /// <summary>
        /// Arithmetic operator that means "equal to" and is used within a query. 
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Eq"/> CAML object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Eq", Justification = "Eq is the correct name in CAML"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Eq", Justification = "Eq is the correct name in CAML")]
        public static Eq Eq(FieldRef fieldRef, Value value)
        {
            return new Eq(fieldRef, value);
        }

        /// <summary>
        /// Arithmetic operator that means "not equal to" and is used in queries.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Neq"/> CAML object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Neq", Justification = "Neq is the correct name in CAML")]
        public static Neq Neq(FieldRef fieldRef, Value value)
        {
            return new Neq(fieldRef, value);
        }

        /// <summary>
        /// Searches for a string at the start of a column that holds Text or Note field type values.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="BeginsWith"/> CAML Object</returns>
        public static BeginsWith BeginsWith(FieldRef fieldRef, Value value)
        {
            return new BeginsWith(fieldRef, value);
        }

        /// <summary>
        /// Searches for a string anywhere within a column that holds Text or Note field type values. 
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Contains"/> CAML Object</returns>
        public static Contains Contains(FieldRef fieldRef, Value value)
        {
            return new Contains(fieldRef, value);
        }

        /// <summary>
        /// Arithmetic operator that means "greater than or equal to." This element can be used within a Where element in a query.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Geq"/> CAML Class</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Geq", Justification = "Geq is the correct name in CAML")]
        public static Geq Geq(FieldRef fieldRef, Value value)
        {
            return new Geq(fieldRef, value);
        }

        /// <summary>
        /// Arithmetic operator that means "less than" and is used in queries in views. This element is used similarly to the <see cref="Eq"/> and <see cref="Gt"/> elements.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Lt"/> CAML object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Lt", Justification = "Lt is the correct name in CAML")]
        public static Lt Lt(FieldRef fieldRef, Value value)
        {
            return new Lt(fieldRef, value);
        }

        /// <summary>
        /// Arithmetic operator that means "greater than." This element is used similarly to the <see cref="Eq"/> and <see cref="Lt"/> elements.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Gt"/> CAML object</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Gt", Justification = "Gt is the correct name in CAML"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gt", Justification = "Gt is the correct name in CAML")]
        public static Gt Gt(FieldRef fieldRef, Value value)
        {
            return new Gt(fieldRef, value);
        }

        /// <summary>
        /// Used within a query to return items that are empty (Null).
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <returns>A <see cref="IsNotNull"/> CAML object</returns>
        public static IsNotNull IsNotNull(FieldRef fieldRef)
        {
            return new IsNotNull(fieldRef);
        }

        /// <summary>
        /// If the specified field is a Lookup field that allows multiple values, specifies that the Value element is included in the list item for the field that is specified by the FieldRef element.
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <returns>A <see cref="Includes"/> CAML object</returns>
        public static Includes Includes(FieldRef fieldRef, Value value)
        {
            return new Includes(fieldRef, value);
        }
        #endregion

        #region List Schema

        /// <summary>
        /// The RowLimit element sets the row limit for a view.
        /// </summary>
        /// <param name="limit">Maximum number of item that the query needs to return</param>
        /// <returns>A <see cref="RowLimit"/> CAML object</returns>
        public static RowLimit RowLimit(int limit)
        {
            return new RowLimit(limit);
        }

        /// <summary>
        /// Provides an enumeration of the fields in a view through a listing of the FieldRef elements.
        /// </summary>
        /// <param name="fieldRef">The <see cref="FieldRef"/> to include</param>
        /// <param name="fieldRefs">Optional <see cref="FieldRef"/> to include</param>
        /// <returns>A <see cref="ViewFields"/> CAML object</returns>
        public static ViewFields ViewFields(FieldRef fieldRef, params FieldRef[] fieldRefs)
        {
            return new ViewFields(fieldRef, fieldRefs);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="query">A <see cref="Query"/> object to include</param>
        /// <returns>A <see cref="View"/> CAML object </returns>
        public static View View(Query query)
        {
            return new View(query);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="query">A <see cref="Query"/> object to include</param>
        /// <param name="viewFields">The fields to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(Query query, ViewFields viewFields)
        {
            return new View(query, viewFields);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="viewFields">The Fields to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(ViewFields viewFields)
        {
            return new View(viewFields);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="rowLimit">The <see cref="RowLimit"/> to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(RowLimit rowLimit)
        {
            return new View(rowLimit);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="query">The <see cref="Query"/> to include</param>
        /// <param name="rowLimit">The <see cref="RowLimit"/> to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(Query query, RowLimit rowLimit)
        {
            return new View(query, rowLimit);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="query">The <see cref="Query"/> to include</param>
        /// <param name="viewFields">The Fields to include</param>
        /// <param name="rowLimit">The <see cref="RowLimit"/> to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(Query query, ViewFields viewFields, RowLimit rowLimit)
        {
            return new View(query, viewFields, rowLimit);
        }

        /// <summary>
        /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
        /// </summary>
        /// <param name="viewFields">The Fields to include</param>
        /// <param name="rowLimit">The <see cref="RowLimit"/> to include</param>
        /// <returns>A <see cref="View"/> CAML object</returns>
        public static View View(ViewFields viewFields, RowLimit rowLimit)
        {
            return new View(viewFields, rowLimit);
        }

        #region Queries

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="where">The <see cref="Where"/> to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(Where where)
        {
            return Query(where, null, null);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="groupBy">The <see cref="GroupBy"/> object to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(GroupBy groupBy)
        {
            return Query(null, null, groupBy);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="orderBy">The <see cref="OrderBy"/> to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(OrderBy orderBy)
        {
            return Query(null, orderBy, null);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="where">The <see cref="Where"/> to include</param>
        /// <param name="groupBy">The <see cref="GroupBy"/> object to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(Where where, GroupBy groupBy)
        {
            return Query(where, null, groupBy);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="where">The <see cref="Where"/> to include</param>
        /// <param name="orderBy">The <see cref="OrderBy"/> to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(Where where, OrderBy orderBy)
        {
            return Query(where, orderBy, null);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="groupBy">The <see cref="GroupBy"/> object to include</param>
        /// <param name="orderBy">The <see cref="OrderBy"/> to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(GroupBy groupBy, OrderBy orderBy)
        {
            return Query(null, orderBy, groupBy);
        }

        /// <summary>
        /// Defines the query for a view.
        /// </summary>
        /// <param name="where">The <see cref="Where"/> to include</param>
        /// <param name="orderBy">The <see cref="OrderBy"/> to include</param>
        /// <param name="groupBy">The <see cref="GroupBy"/> object to include</param>
        /// <returns>A <see cref="Query"/> CAML object</returns>
        public static Query Query(Where where, OrderBy orderBy, GroupBy groupBy)
        {
            return new Query(where, orderBy, groupBy);
        }

        #endregion

        /// <summary>
        /// Used within the context of a query to specify a filter.
        /// </summary>
        /// <param name="child">The where child to include</param>
        /// <returns>A <see cref="Where"/> CAML object</returns>
        public static Where Where(IWhereChild child)
        {
            return new Where(child);
        }
        #endregion
    }

    #region Helper Types

    /// <summary>
    /// Provide helper method while creating
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
    public static class CamlHelper
    {
        /// <summary>
        /// Create a new CAML that close without a value
        /// </summary>
        /// <param name="name">Name of the element</param>
        /// <param name="attributes">Optional CAML attributes</param>
        /// <returns>CAML string</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
        public static string BuildCaml(string name, params CamlPart[] attributes)
        {
            return string.Format(CultureInfo.CurrentCulture, "<{0}{1}/>", name, BuildAttributes(attributes));
        }

        /// <summary>
        /// Creates a new CAML
        /// </summary>
        /// <param name="name">Name of the element</param>
        /// <param name="value">Value of the element</param>
        /// <param name="attributes">Optional CAML attributes</param>
        /// <returns>CAML text</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
        public static string BuildCaml(string name, string value, params CamlPart[] attributes)
        {
            return string.Format(CultureInfo.CurrentCulture, "<{0}{1}>{2}</{0}>", name, BuildAttributes(attributes), value);
        }

        /// <summary>
        /// Helper that merges CAML elements to create CAML text
        /// </summary>
        /// <param name="camlElements">Elements to merge CAML</param>
        /// <returns>CAML text</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "caml", Justification = "caml is the correct for this type")]
        public static string CombineCamlElements(params ICamlElement[] camlElements)
        {
            string caml = string.Empty;
            foreach (ICamlElement element in camlElements.Where(x => x != null))
            {
                caml += element.ToCaml();
            }

            return caml;
        }

        /// <summary>
        /// Translate the null able Boolean to a CAML value
        /// </summary>
        /// <param name="value">Value to translate</param>
        /// <returns>TRUE when true otherwise FALSE</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
        public static string ToCaml(bool? value)
        {
            return value.GetValueOrDefault(false) ? "TRUE" : "FALSE";
        }

        /// <summary>
        /// Translate the Boolean to a CAML value
        /// </summary>
        /// <param name="value">Boolean to translate</param>
        /// <returns>TRUE when value is true otherwise FALSE</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
        public static string ToCaml(bool value)
        {
            return value ? "TRUE" : "FALSE";
        }

        /// <summary>
        /// Build the attributes a returns the CAML
        /// </summary>
        /// <param name="attributes">Attributes for the CAML</param>
        /// <returns>CAML text</returns>
        private static string BuildAttributes(params CamlPart[] attributes)
        {
            string atts = string.Empty;

            // include only the attributes that has a value
            foreach (CamlPart att in attributes)
            {
                if (att != null && att.Value != null)
                {
                    atts += " " + string.Format(CultureInfo.CurrentCulture, "{0} = \"{1}\"", att.Name, att.Value) + " ";
                }
            }

            return atts;
        }
    }

    /// <summary>
    /// Represents a part of a CAML text
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is the correct for this type")]
    public class CamlPart
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, string value)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            this.Name = name;
            this.Value = value;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, int value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, bool value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, char value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, decimal value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, double value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, float value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, long value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, short value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, uint value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, ulong value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CamlPart"/> class
        /// </summary>
        /// <param name="name">Name of the attribute</param>
        /// <param name="value">Value of the attribute</param>
        public CamlPart(string name, ushort value)
            : this(name, value.ToString(CultureInfo.CurrentCulture))
        {
        }

        /// <summary>
        /// Gets the Name of the CAML Attribute
        /// </summary>
        public string Name
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the Value of the CAML Attribute
        /// </summary>
        public string Value
        {
            get;
            private set;
        }
    }

    #endregion

    #region CAML abstract classes

    /// <summary>
    /// A class defining a base for the CAML element
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Caml", Justification = "Caml is correct as is in CAML"),
    DebuggerStepThrough]
    public abstract class CamlElement : ICamlElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CamlElement"/> class
        /// </summary>
        /// <param name="elementName">Name of the CAML element</param>
        protected CamlElement(string elementName)
        {
            if (string.IsNullOrEmpty(elementName))
            {
                throw new ArgumentNullException("elementName");
            }

            this.ElementName = elementName;
        }

        /// <summary>
        /// Gets the name of the element
        /// </summary>
        protected string ElementName
        {
            get;
            private set;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public virtual string ToCaml()
        {
            return CamlHelper.BuildCaml(this.ElementName);
        }
    }

    /// <summary>
    /// Class defining the base of a Field Ref Element
    /// </summary>
    [DebuggerStepThrough]
    public abstract class FieldRefElement : CamlElement, IWhereChild
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="FieldRefElement"/> class
        /// </summary>
        /// <param name="elementName">Name of the CAML element</param>
        /// <param name="fieldRef">The FieldRef of this element</param>
        protected FieldRefElement(string elementName, FieldRef fieldRef)
            : base(elementName)
        {
            if (fieldRef == null)
            {
                throw new ArgumentNullException("fieldRef");
            }

            FieldRef = fieldRef;
        }

        /// <summary>
        /// Gets the <see cref="FieldRef"/> of the element
        /// </summary>
        protected FieldRef FieldRef
        {
            get;
            private set;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public override string ToCaml()
        {
            return CamlHelper.BuildCaml(this.ElementName, this.FieldRef.ToCaml());
        }
    }

    /// <summary>
    /// Class defining the base for a Field Ref Value element
    /// </summary>
    [DebuggerStepThrough]
    public abstract class FieldRefValueElement : FieldRefElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="FieldRefValueElement"/> class
        /// </summary>
        /// <param name="elementName">Name of the CAML element</param>
        /// <param name="fieldRef">The Field Ref</param>
        /// <param name="value">The value</param>
        protected FieldRefValueElement(string elementName, FieldRef fieldRef, Value value)
            : base(elementName, fieldRef)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Value = value;
        }

        /// <summary>
        /// Gets the value
        /// </summary>
        protected Value Value
        {
            get;
            private set;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public override string ToCaml()
        {
            return CamlHelper.BuildCaml(this.ElementName, CamlHelper.CombineCamlElements(this.FieldRef, this.Value));
        }
    }

    /// <summary>
    /// Class defining the base for an and or or element
    /// </summary>
    [DebuggerStepThrough]
    public abstract class AndOrElement : CamlElement, IWhereChild
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AndOrElement"/> class
        /// </summary>
        /// <param name="elementName">Name of the element</param>
        /// <param name="child1">First child for the And/Or</param>
        /// <param name="child2">Second child for the And/Or</param>
        protected AndOrElement(string elementName, IWhereChild child1, IWhereChild child2)
            : base(elementName)
        {
            if (child1 == null)
            {
                throw new ArgumentNullException("child1");
            }

            if (child2 == null)
            {
                throw new ArgumentNullException("child2");
            }

            this.Child1 = child1;
            this.Child2 = child2;
        }

        /// <summary>
        /// Gets the first child
        /// </summary>
        protected IWhereChild Child1
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the second child
        /// </summary>
        protected IWhereChild Child2
        {
            get;
            private set;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public override string ToCaml()
        {
            return CamlHelper.BuildCaml(this.ElementName, CamlHelper.CombineCamlElements(this.Child1, this.Child2));
        }
    }

    #endregion

    #region Logical Joins

    /// <summary>
    /// Used within the <code>Where</code> element to group filters in a query for a view.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "And", Justification = "And is correct as is in CAML"),
    DebuggerStepThrough]
    public class And : AndOrElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="And"/> class
        /// </summary>
        /// <param name="child1">First child CAML element</param>
        /// <param name="child2">Second child CAML element</param>
        public And(IWhereChild child1, IWhereChild child2)
            : base("And", child1, child2)
        {
        }
    }

    /// <summary>
    /// Used within the <code>Where</code> element to group filters in a query.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Or", Justification = "Or is correct as is in CAML"),
    DebuggerStepThrough]
    public class Or : AndOrElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Or"/> class
        /// </summary>
        /// <param name="child1">First child CAML element</param>
        /// <param name="child2">Second child CAML element</param>
        public Or(IWhereChild child1, IWhereChild child2)
            : base("Or", child1, child2)
        {
        }
    }

    #endregion

    #region Group/Order Operations

    /// <summary>
    /// Contains a Group By section for grouping the data returned through a query in a list view.
    /// </summary>
    [DebuggerStepThrough]
    public class GroupBy : ICamlElement
    {
        /// <summary>
        /// Field containing the collapse attribute
        /// </summary>
        private CamlPart collapsible;

        /// <summary>
        /// Field containing the field ref field
        /// </summary>
        private FieldRef fieldRef;

        /// <summary>
        /// Initializes a new instance of the <see cref="GroupBy"/> class
        /// </summary>
        /// <param name="fieldRef">Field Ref used for the group by</param>
        public GroupBy(FieldRef fieldRef)
            : this(fieldRef, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GroupBy"/> class
        /// </summary>
        /// <param name="fieldRef"><see cref="FieldRef"/> used for the <see cref="GroupBy"/></param>
        /// <param name="collapse">Value indicating to collapse the <see cref="GroupBy"/></param>
        public GroupBy(FieldRef fieldRef, bool? collapse)
        {
            this.fieldRef = fieldRef;
            if (collapse.HasValue)
            {
                this.collapsible = new CamlPart("Collapse", collapse.Value);
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("GroupBy", this.fieldRef.ToCaml(), this.collapsible);
        }
    }

    /// <summary>
    /// Determines the sort order for a query. The OrderBy element contains a group of FieldRef elements.
    /// </summary>
    [DebuggerStepThrough]
    public class OrderBy : ICamlElement
    {
        /// <summary>
        /// Field containing a array of field refs
        /// </summary>
        private FieldRef[] fieldRefs;

        /// <summary>
        /// Fields containing the override attribute
        /// </summary>
        private CamlPart overide;

        /// <summary>
        /// Field containing the index for order by attribute
        /// </summary>
        private CamlPart useIndexForOrderBy;

        /// <summary>
        /// Initializes a new instance of the <see cref="OrderBy"/> class
        /// </summary>
        /// <param name="fieldRef"><see cref="FieldRef"/> used for the <see cref="OrderBy"/></param>
        public OrderBy(params FieldRef[] fieldRef)
            : this(null, null, fieldRef)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="OrderBy"/> class
        /// </summary>
        /// <param name="overrideOrderBy">Value indicating whenever to override</param>
        /// <param name="useIndexForOrderBy">Value indicating whenever to use the index for an order by</param>
        /// <param name="fieldRef"><see cref="FieldRef"/> used for the <see cref="OrderBy"/></param>
        public OrderBy(bool? overrideOrderBy, bool? useIndexForOrderBy, params FieldRef[] fieldRef)
        {
            this.fieldRefs = fieldRef;
            if (overrideOrderBy.HasValue)
            {
                this.overide = new CamlPart("Override", CamlHelper.ToCaml(overrideOrderBy.Value));
            }

            if (useIndexForOrderBy.HasValue)
            {
                this.useIndexForOrderBy = new CamlPart("UseIndexForOrderBy", CamlHelper.ToCaml(useIndexForOrderBy.Value));
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            string fielref = string.Empty;
            foreach (FieldRef fr in this.fieldRefs)
            {
                fielref = fr.ToCaml();
            }

            return CamlHelper.BuildCaml("OrderBy", fielref, this.overide, this.useIndexForOrderBy);
        }
    }

    #endregion

    #region Value Child Elements

    /// <summary>
    /// Renders the current date in the format that is relative to the server's local time zone. For servers in the United States, the format is MM/DD/YYYY (for example, 1/21/2001).
    /// </summary>
    [DebuggerStepThrough]
    public class Today : CamlElement, IValueChild
    {
        /// <summary>
        /// Field that contains the offset
        /// </summary>
        private CamlPart offset;

        /// <summary>
        /// Initializes a new instance of the <see cref="Today"/> class
        /// </summary>
        public Today()
            : base("Today")
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Today"/> class
        /// </summary>
        /// <param name="offset">Adds or subtracts the number of days that are specified by the positive or negative integer value.</param>
        public Today(int offset)
            : base("Today")
        {
            this.offset = new CamlPart("Offset", offset);
        }

        /// <summary>
        /// Gets the type of the value
        /// </summary>
        public string Type
        {
            get
            {
                return "DateTime";
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public override string ToCaml()
        {
            return CamlHelper.BuildCaml("Today", this.offset);
        }
    }

    /// <summary>
    /// Returns the current date and time.
    /// </summary>
    [DebuggerStepThrough]
    public class Now : CamlElement, IValueChild
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Now"/> class
        /// </summary>
        public Now()
            : base("Now")
        {
        }

        /// <summary>
        /// Gets the type of the value
        /// </summary>
        public string Type
        {
            get
            {
                return "DateTime";
            }
        }
    }

    /// <summary>
    /// Contains the unique ID number of the currently authenticated user of a site, as defined in the UserInfo table of the content database.
    /// </summary>
    [DebuggerStepThrough]
    public class UserId : CamlElement, IValueChild
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="UserId"/> class
        /// </summary>
        public UserId()
            : base("UserID")
        {
        }

        /// <summary>
        /// Gets the type of the value
        /// </summary>
        public string Type
        {
            get
            {
                return string.Empty;
            }
        }
    }

    #endregion

    #region Comparison Operators

    /// <summary>
    /// Arithmetic operator that means "equal to" and is used within a query. 
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Eq", Justification = "Eq is correct as is in CAML"),
    System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Eq", Justification = "Eq is correct as is in CAML"),
    DebuggerStepThrough]
    public class Eq : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Eq"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Eq(FieldRef fieldRef, Value value)
            : base("Eq", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Arithmetic operator that means "not equal to" and is used in queries.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Neq", Justification = "Neq is correct as is in CAML"),
    DebuggerStepThrough]
    public class Neq : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Neq"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Neq(FieldRef fieldRef, Value value)
            : base("Neq", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Searches for a string at the start of a column that holds Text or Note field type values.
    /// </summary>
    [DebuggerStepThrough]
    public class BeginsWith : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="BeginsWith"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public BeginsWith(FieldRef fieldRef, Value value)
            : base("BeginsWith", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Searches for a string anywhere within a column that holds Text or Note field type values.  
    /// </summary>
    [DebuggerStepThrough]
    public class Contains : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Contains"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Contains(FieldRef fieldRef, Value value)
            : base("Contains", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Arithmetic operator that means "greater than or equal to." This element can be used within a Where element in a query.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Geq", Justification = "Geq is correct as is in CAML"),
    DebuggerStepThrough]
    public class Geq : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Geq"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Geq(FieldRef fieldRef, Value value)
            : base("Geq", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Arithmetic operator that means "less than" and is used in queries in views. This element is used similarly to the <see cref="Eq"/> and <see cref="Gt" /> elements.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Lt", Justification = "Lt is correct as is in CAML"),
    DebuggerStepThrough]
    public class Lt : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Lt"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Lt(FieldRef fieldRef, Value value)
            : base("Lt", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Arithmetic operator that means "greater than." This element is used similarly to the <see cref="Eq"/> and <see cref="Lt"/> elements.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Gt", Justification = "Gt is correct as is in CAML"),
    System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Gt", Justification = "Gt is correct as is in CAML"),
    DebuggerStepThrough]
    public class Gt : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Gt"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Gt(FieldRef fieldRef, Value value)
            : base("Gt", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// If the specified field is a Lookup field that allows multiple values, specifies that the Value element is included in the list item for the field that is specified by the FieldRef element.
    /// </summary>
    [DebuggerStepThrough]
    public class Includes : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Includes"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Includes(FieldRef fieldRef, Value value)
            : base("Includes", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Used within a query to return items that are not empty (Null).
    /// </summary>
    [DebuggerStepThrough]
    public class IsNotNull : FieldRefElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="IsNotNull"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        public IsNotNull(FieldRef fieldRef)
            : base("IsNotNull", fieldRef)
        {
        }
    }

    /// <summary>
    /// Used within a query to return items that are empty (Null).
    /// </summary>
    [DebuggerStepThrough]
    public class IsNull : FieldRefElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="IsNull"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        public IsNull(FieldRef fieldRef)
            : base("IsNull", fieldRef)
        {
        }
    }

    /// <summary>
    /// Specifies whether the value of a list item for the field specified by the FieldRef element is equal to one of the values specified by the Values element.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "In", Justification = "In is correct as is in CAML"),
    DebuggerStepThrough]
    public class In : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="In"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public In(FieldRef fieldRef, Value value)
            : base("In", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Arithmetic operator that means "less than or equal to." The <see cref="Leq"/> element is used in view queries similarly to the <see cref="Eq"/> and <see cref="Geq" /> elements.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Leq", Justification = "Leq is correct in CAML"),
    DebuggerStepThrough]
    public class Leq : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Leq"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public Leq(FieldRef fieldRef, Value value)
            : base("Leq", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// If the specified field is a Lookup field that allows multiple values, specifies that the Value element is excluded from the list item for the field that is specified by the FieldRef element.
    /// </summary>
    [DebuggerStepThrough]
    public class NotIncludes : FieldRefValueElement
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="NotIncludes"/> class
        /// </summary>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        public NotIncludes(FieldRef fieldRef, Value value)
            : base("NotIncludes", fieldRef, value)
        {
        }
    }

    /// <summary>
    /// Defines a filter based on the type of membership for the user.
    /// </summary>
    [DebuggerStepThrough]
    public class Membership : IWhereChild
    {
        /// <summary>
        /// Field containing the field ref
        /// </summary>
        private FieldRef fieldRef;

        /// <summary>
        /// Field containing the type attribute
        /// </summary>
        private CamlPart typeAttribute;

        /// <summary>
        /// Initializes a new instance of the <see cref="Membership"/> class
        /// </summary>
        /// <param name="type">Specifies the type of membership for the user. Possible values include the following:</param>
        /// <param name="fieldRef">Represents a reference to a field within a query.</param>
        public Membership(MembershipType type, FieldRef fieldRef)
        {
            if (fieldRef == null)
            {
                throw new ArgumentNullException("fieldRef");
            }

            this.typeAttribute = new CamlPart("Type", type.ToString());
            this.fieldRef = fieldRef;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("Membership", this.fieldRef.ToCaml(), this.typeAttribute);
        }
    }

    #endregion

    #region Field Value Operators

    /// <summary>
    /// Contains the value against which the value returned by the <code>FieldRef</code> element is compared.
    /// </summary>
    [DebuggerStepThrough]
    public class Value : ICamlElement
    {
        /// <summary>
        /// Field containing a value indicating whenever to include the time value
        /// </summary>
        private CamlPart includeTimeValue;

        /// <summary>
        /// Field containing the type attribute
        /// </summary>
        private CamlPart typeAttribute;

        /// <summary>
        /// Field containing the value
        /// </summary>
        private string value;

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="child">Child to include to this <see cref="Value"/></param>
        public Value(IValueChild child)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            this.typeAttribute = new CamlPart("Type", child.Type);
            this.value = child.ToCaml();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="child">Child to include to this <see cref="Value"/></param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(IValueChild child, bool? includeTimeValue)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            this.typeAttribute = new CamlPart("Type", child.Type);

            if (includeTimeValue.HasValue)
            {
                this.includeTimeValue = new CamlPart("IncludeTimeValue", includeTimeValue.Value);
            }

            this.value = child.ToCaml();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(int data)
            : this("Number", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(bool data)
            : this("Bool", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(decimal data)
            : this("Number", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(double data)
            : this("Number", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(float data)
            : this("Number", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(long data)
            : this("Number", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        public Value(string data)
            : this("Text", data, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(int data, bool? includeTimeValue)
            : this("Number", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(bool data, bool? includeTimeValue)
            : this("Bool", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(decimal data, bool? includeTimeValue)
            : this("Number", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(double data, bool? includeTimeValue)
            : this("Number", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(float data, bool? includeTimeValue)
            : this("Number", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(long data, bool? includeTimeValue)
            : this("Number", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(string data, bool? includeTimeValue)
            : this("Text", data, includeTimeValue)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Value"/> class
        /// </summary>
        /// <param name="type">Type that defines the data</param>
        /// <param name="data">Value that represents the data for this <see cref="Value"/> instance</param>
        /// <param name="includeTimeValue">Value indicating whenever to the data of this <see cref="Value"/> is a time value</param>
        public Value(string type, object data, bool? includeTimeValue)
        {
            if (string.IsNullOrEmpty(type))
            {
                throw new ArgumentNullException("type");
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            this.typeAttribute = new CamlPart("Type", type);
            if (includeTimeValue.HasValue)
            {
                this.includeTimeValue = new CamlPart("IncludeTimeValue", includeTimeValue.Value);
            }

            this.value = data.ToString();
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("Value", this.value, this.typeAttribute, this.includeTimeValue);
        }
    }

    /// <summary>
    /// Represents a reference to a field within a query.
    /// </summary>
    [DebuggerStepThrough]
    public class FieldRef : ICamlElement
    {
        /// <summary>
        /// Field containing the name of the field
        /// </summary>
        private CamlPart name;

        /// <summary>
        /// Field containing the lookup of the field
        /// </summary>
        private CamlPart lookupId;

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldRef"/> class
        /// </summary>
        /// <param name="name">Provides the internal name of the field that is referenced.</param>
        public FieldRef(string name)
            : this(name, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldRef"/> class
        /// </summary>
        /// <param name="name">Name of the Field</param>
        /// <param name="isLookupId">Value indicating whenever this is a lookup Id</param>
        public FieldRef(string name, bool? isLookupId)
        {
            this.name = new CamlPart("Name", name);

            if (isLookupId.HasValue)
            {
                this.lookupId = new CamlPart("LookupId", isLookupId.Value);
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            if (this.lookupId != null)
            {
                return CamlHelper.BuildCaml("FieldRef", this.name, this.lookupId);
            }
            else
            {
                return CamlHelper.BuildCaml("FieldRef", this.name);
            }
        }
    }

    /// <summary>
    /// Multiple Values
    /// </summary>
    [DebuggerStepThrough]
    public class Values : ICamlElement
    {
        /// <summary>
        /// Field that holds a list containing the values
        /// </summary>
        private List<Value> values = new List<Value>();

        /// <summary>
        /// Initializes a new instance of the <see cref="Values"/> class
        /// </summary>
        /// <param name="value">Contains the value against which the value returned by the <code>FieldRef</code> element is compared.</param>
        /// <param name="values">Optional values </param>
        public Values(Value value, params Value[] values)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            this.values.Add(value);
            if (values.Any())
            {
                this.values.AddRange(values);
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            string caml = string.Empty;
            this.values.ForEach(c => caml += c.ToCaml());

            return CamlHelper.BuildCaml("Values", caml);
        }
    }

    #endregion

    #region List Schema

    /// <summary>
    /// The RowLimit element sets the row limit for a view.
    /// </summary>
    [DebuggerStepThrough]
    public class RowLimit : ICamlElement
    {
        /// <summary>
        /// Field contain the row limit
        /// </summary>
        private int rowLimit;

        /// <summary>
        /// Initializes a new instance of the <see cref="RowLimit"/> class
        /// </summary>
        /// <param name="rowLimit">Value representing the limit</param>
        public RowLimit(int rowLimit)
        {
            if (rowLimit < 0)
            {
                throw new ArgumentException("Row Limit cannot be less than zero (0)", "rowLimit");
            }

            this.rowLimit = rowLimit;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("RowLimit", this.rowLimit.ToString(CultureInfo.CurrentCulture));
        }
    }

    /// <summary>
    /// Provides an enumeration of the fields in a view through a listing of the FieldRef elements.
    /// </summary>
    [DebuggerStepThrough]
    public class ViewFields : ICamlElement
    {
        /// <summary>
        /// Field holding a list containing the field Refs
        /// </summary>
        private List<FieldRef> fieldRefs = new List<FieldRef>();

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewFields"/> class
        /// </summary>
        /// <param name="fieldRef">FieldRef that needs to included to the view</param>
        /// <param name="fieldRefs">Other fields to needs to included in the view</param>
        public ViewFields(FieldRef fieldRef, params FieldRef[] fieldRefs)
        {
            if (fieldRef == null)
            {
                throw new ArgumentNullException("fieldRef");
            }

            this.fieldRefs.Add(fieldRef);
            if (fieldRefs.Any())
            {
                this.fieldRefs.AddRange(fieldRefs);
            }
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            string caml = string.Empty;
            this.fieldRefs.ForEach(c => caml += c.ToCaml());

            return CamlHelper.BuildCaml("ViewFields", caml);
        }
    }

    /// <summary>
    /// In a list definition (Schema.xml), defines a view for a list in a Web site based on Microsoft SharePoint Foundation, where each list can contain a number of views.
    /// </summary>
    [DebuggerStepThrough]
    public class View : ICamlElement
    {
        /// <summary>
        /// Field holding the query
        /// </summary>
        private Query query;

        /// <summary>
        /// Field holding the view fields
        /// </summary>
        private ViewFields viewFields;

        /// <summary>
        /// Field holding the row limit
        /// </summary>
        private RowLimit rowLimit;

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="rowLimit">Limit of row of this view</param>
        public View(RowLimit rowLimit)
            : this(null, null, rowLimit)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="query">Query of the View</param>
        public View(Query query)
            : this(query, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="query">Query of the View</param>
        /// <param name="rowLimit">Limit of row of this view</param>
        public View(Query query, RowLimit rowLimit)
            : this(query, null, rowLimit)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="viewFields">Fields the this view includes</param>
        public View(ViewFields viewFields)
            : this(null, viewFields, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="viewFields">Fields the this view includes</param>
        /// <param name="rowLimit">Limit of row of this view</param>
        public View(ViewFields viewFields, RowLimit rowLimit)
            : this(null, viewFields, rowLimit)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="query">Query of the View</param>
        /// <param name="viewFields">Fields the this view includes</param>
        public View(Query query, ViewFields viewFields)
            : this(query, viewFields, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="View"/> class
        /// </summary>
        /// <param name="query">Query of the View</param>
        /// <param name="viewFields">Fields the this view includes</param>
        /// <param name="rowLimit">Limit of row of this view</param>
        public View(Query query, ViewFields viewFields, RowLimit rowLimit)
        {
            this.query = query;
            this.viewFields = viewFields;
            this.rowLimit = rowLimit;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("View", CamlHelper.CombineCamlElements(this.query, this.viewFields, this.rowLimit));
        }
    }

    /// <summary>
    /// Defines the query for a view.
    /// </summary>
    [DebuggerStepThrough]
    public class Query : ICamlElement
    {
        /// <summary>
        /// Field holding the where
        /// </summary>
        private Where where;

        /// <summary>
        /// Field holding the order by
        /// </summary>
        private OrderBy orderBy;

        /// <summary>
        /// Field holding the group by
        /// </summary>
        private GroupBy groupBy;

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="where">Where CAML where this Query is based on</param>
        public Query(Where where)
            : this(where, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="groupBy">Specifies whenever this query is grouped by</param>
        public Query(GroupBy groupBy)
            : this(null, null, groupBy)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="orderBy">Specifies the Order of the result</param>
        public Query(OrderBy orderBy)
            : this(null, orderBy, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="where">Where CAML where this Query is based on</param>
        /// <param name="groupBy">Specifies whenever this query is grouped by</param>
        public Query(Where where, GroupBy groupBy)
            : this(where, null, groupBy)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="where">Where CAML where this Query is based on</param>
        /// <param name="orderBy">Specifies the Order of the result</param>
        public Query(Where where, OrderBy orderBy)
            : this(where, orderBy, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="orderBy">Specifies the Order of the result</param>
        /// <param name="groupBy">Specifies whenever this query is grouped by</param>
        public Query(OrderBy orderBy, GroupBy groupBy)
            : this(null, orderBy, groupBy)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Query"/> class
        /// </summary>
        /// <param name="where">Where CAML where this Query is based on</param>
        /// <param name="orderBy">Specifies the Order of the result</param>
        /// <param name="groupBy">Specifies whenever this query is grouped by</param>
        public Query(Where where, OrderBy orderBy, GroupBy groupBy)
        {
            this.where = where;
            this.orderBy = orderBy;
            this.groupBy = groupBy;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("Query", CamlHelper.CombineCamlElements(this.orderBy, this.where, this.groupBy));
        }
    }

    /// <summary>
    /// Used within the context of a query to specify a filter.
    /// </summary>
    [DebuggerStepThrough]
    public class Where : ICamlElement
    {
        /// <summary>
        /// Field holding the child
        /// </summary>
        private IWhereChild child;

        /// <summary>
        /// Initializes a new instance of the <see cref="Where"/> class
        /// </summary>
        /// <param name="child">Child for the where</param>
        public Where(IWhereChild child)
        {
            this.child = child;
        }

        /// <summary>
        /// Translate the current CAML element into a CAML string
        /// </summary>
        /// <returns>CAML text</returns>
        public string ToCaml()
        {
            return CamlHelper.BuildCaml("Where", this.child.ToCaml());
        }
    }

    #endregion

}
